<?php

namespace ASW\Utility;

use ASW\Utility\Enums\PhpErrorLevel;
use ASW\Utility\Logging\Logger;
use ASW\Utility\Logging\LogLevel;
use ASW\Utility\Logging\Providers\FileLogProvider;
use ASW\Utility\Logging\Providers\TerminalLogProvider;
use Throwable;

final class Sys
{
    /**
     * @param string $appRoot 项目根目录
     * @return void
     */
    public static function init(string $appRoot): void
    {
        $constFile = "$appRoot/config/const.php";
        if (file_exists($constFile)) require_once $constFile;
        Config::load("$appRoot/config/config.php");

        error_reporting(E_ALL & ~E_NOTICE);
        set_error_handler([__CLASS__, "errorHandler"], E_ALL & ~E_NOTICE);
        set_exception_handler([__CLASS__, "exceptionHandler"]);

        $timeZone = Config::get('system/timezone', 'PRC');
        date_default_timezone_set($timeZone);

        $logLevelName = Config::get('system/logLevel', LogLevel::DEBUG->name);
        $logLevel     = LogLevel::tryFrom($logLevelName);
        Logger::addProvider(new TerminalLogProvider($logLevel));
        Logger::addProvider(new FileLogProvider($logLevel));
    }

    public static function errorHandler(int $level, string $message, string $file, int $line): void
    {
        $phpErrorName = PhpErrorLevel::tryFrom($level)->name;
        $traceArray   = debug_backtrace();
        // var_export($traceArray);
        $traceArray = array_splice($traceArray, 1);
        $transLines = [];
        foreach ($traceArray as $trace) {
            $class = $trace['class'] ?? '';
            $methodArgs     = '';
            $methodCallType = $trace['type'] ?? '';
            if (!empty($methodCallType)) $methodCallType = $methodCallType === 'nothing' ? '' : $methodCallType;
            $traceFile = $trace['file'] ?? '';
            if (!empty($traceFile)) $traceFile = "in $traceFile line {$trace['line']}";
            $transLines[] = "at $class$methodCallType{$trace['function']}($methodArgs) $traceFile";
        }
        $traceString = implode("\n", $transLines);
        Logger::get('UnHandledError')->error("[$phpErrorName] $message\nat $file line $line\ntrace:\n$traceString");
    }

    public static function exceptionHandler(Throwable $ex): void
    {
        Logger::get('UnHandledException')->error($ex->getMessage(), $ex);
    }
}